package com.huishu.order.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.huishu.commons.config.cache.RedisUtil;
import com.huishu.commons.constant.RedisKeyPrefix;
import com.huishu.commons.constant.SmsTemplateCode;
import com.huishu.commons.constant.WxConstact;
import com.huishu.commons.exception.BaseException;
import com.huishu.commons.exception.NotFoundException;
import com.huishu.commons.pojo.Result;
import com.huishu.commons.pojo.dto.*;
import com.huishu.commons.pojo.model.UserDO;
import com.huishu.commons.pojo.vo.CouponVO;
import com.huishu.commons.pojo.vo.UserMemberVO;
import com.huishu.commons.pojo.vo.UserOrderInfoVO;
import com.huishu.commons.utlis.*;
import com.huishu.order.component.LocalCache;
import com.huishu.order.component.OrderMessageSender;
import com.huishu.order.config.MyWXConfig;
import com.huishu.order.config.YaDunApiInfoEntity;
import com.huishu.order.execl.OrderExecl;
import com.huishu.order.fegin.CouponFeignClient;
import com.huishu.order.fegin.GoodsFeignClient;
import com.huishu.order.fegin.UserFeignClient;
import com.huishu.order.mapper.OrderDeliveryMapper;
import com.huishu.order.mapper.OrderMapper;
import com.huishu.order.pojo.dto.*;
import com.huishu.order.pojo.model.*;
import com.huishu.order.pojo.vo.*;
import com.huishu.order.service.*;
import com.huishu.order.utils.AssistantContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author generator@ljj
 * @since 2023-04-07
 */
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderDO> implements OrderService {

    @Autowired
    private OrderDeliveryMapper orderDeliveryMapper;

    @Autowired
    private YaDunApiInfoEntity yaDunApiInfoEntity;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private Executor executor;

    @Autowired
    private StockServiceImpl stockService;

    @Autowired
    private LocalCache<Boolean> cache;

    @Autowired
    private OrderMessageSender orderMessageSender;

    @Autowired
    private GoodsFeignClient goodsFeignClient;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private CouponFeignClient couponFeignClient;

    @Autowired
    private OrderCouponService orderCouponService;

    @Autowired
    private CartItemService cartItemService;

    @Autowired
    private RefundService refundService;

    @Autowired
    private OrderRemarksService orderRemarksService;

    @Transactional
    @Override
    public Result expressDeliveryNotify(ExpressDeliveryDTO expressDeliveryDTO) {
        // 查询订单
        LambdaQueryWrapper<OrderDO> queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                .eq(OrderDO::getOrderSn, expressDeliveryDTO.getOrderSn());
        OrderDO orderDO = this.getOne(queryWrapper);
        if (orderDO == null) {
            throw new NotFoundException("订单不存在");
        }

        if (StringUtils.isNotEmpty(expressDeliveryDTO.getDeliverySn())) {
            LambdaQueryWrapper<OrderDeliveryDO> queryWrapperOrderDelivery = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                    .eq(OrderDeliveryDO::getOrderSn, expressDeliveryDTO.getOrderSn())
                    .eq(OrderDeliveryDO::getDeliverySn, expressDeliveryDTO.getDeliverySn());
            OrderDeliveryDO orderDeliveryDO = orderDeliveryMapper.selectOne(queryWrapperOrderDelivery);
            if (orderDeliveryDO != null) {
                return Result.fail("当前订单:" + orderDeliveryDO.getOrderSn() + "中 已存在快递单号：" + expressDeliveryDTO.getDeliverySn());
            }
        }
        OrderDeliveryDO orderDeliveryDO = new OrderDeliveryDO();
        orderDeliveryDO.setDeliveryCompany(expressDeliveryDTO.getDeliveryCompany());
        orderDeliveryDO.setDeliverySn(expressDeliveryDTO.getDeliverySn());
        orderDeliveryDO.setOrderSn(orderDO.getOrderSn());
        orderDeliveryDO.setOrderId(orderDO.getId());
        orderDeliveryDO.setDeliveryTime(new Date());
        orderDeliveryMapper.insert(orderDeliveryDO);

        orderDO.setOrderStatus(2);
        boolean b = this.updateById(orderDO);
        if (b) {
            return Result.success();
        }
        throw new BaseException("插入数据失败！");
    }

    @GlobalTransactional(name = "Create-Order-TX", rollbackFor = Exception.class)
    @Override
    public Result createOrder(CreateOrderDTO createOrderDTO, HttpServletRequest request) {
        Result checkSample = checkSample(createOrderDTO);
        if (!checkSample.getStatus()) {
            return checkSample;
        }
        // 检查库存
        Result result = checkStock(createOrderDTO);
        if (!result.getStatus()) {
            return result;
        }
        try {
            // 创建订单数据
            String orderNo = redisUtil.getOrderNo("HS");
            CompletableFuture<OrderDO> future = CompletableFuture.supplyAsync(() -> createOderDO(createOrderDTO, orderNo), executor);
            CompletableFuture<YaDunOrderDTO> future1 = CompletableFuture.supplyAsync(() -> createYaDunOrderDTO(createOrderDTO, orderNo), executor);
            CompletableFuture.runAsync(() -> maintenanceOrderCoupon(createOrderDTO.getCouponIds(), orderNo), executor);
            CompletableFuture<Void> allOf = CompletableFuture.allOf(future, future1);
            allOf.get();
            OrderDO orderDO = future.get();
            YaDunOrderDTO yaDunOrderDTO = future1.get();
            List<OrderItemDO> orderItems = new ArrayList<>();
            BigDecimal integrationAmount = new BigDecimal(0);
            Integer integration = 0;
            for (CreateOrderDTO.OrderProduct orderProduct : createOrderDTO.getOrderProducts()) {
                integration += orderProduct.getIntegration();
                OrderItemDO orderItemDO = new OrderItemDO();
                orderItemDO.setProductId(orderProduct.getId());
                orderItemDO.setProductItemId(orderProduct.getProductItemId());
                orderItemDO.setProductSpecifications(orderProduct.getProductSpecifications());
                orderItemDO.setProductSkuCode(orderProduct.getSkuCode());
                orderItemDO.setAlbumPics(orderProduct.getAlbumPics());
                orderItemDO.setProductName(orderProduct.getName());
                orderItemDO.setProductPrice(orderProduct.getPrice());
                orderItemDO.setProductQuantity(orderProduct.getNum());
                orderItemDO.setProductCategoryId(orderProduct.getProductCategoryId());

                orderItemDO.setProductType(orderProduct.getType());
                orderItemDO.setParentProductId(orderProduct.getParentProductId());

                YaDunOrderDTO.Goods goods = new YaDunOrderDTO.Goods();
                goods.setSku(orderProduct.getSkuCode());
                goods.setGoodsName(orderProduct.getName());
                goods.setNum(orderProduct.getNum());
                goods.setPrice(orderProduct.getPrice() != null ? MoneyUtils.yuanToFen(String.valueOf(orderProduct.getPrice())) : MoneyUtils.yuanToFen(String.valueOf(new BigDecimal(0))));
                goods.setDiscountFee(orderProduct.getPromotionAmount() != null ? MoneyUtils.yuanToFen(String.valueOf(orderProduct.getPromotionAmount())) : MoneyUtils.yuanToFen(String.valueOf(new BigDecimal(0))));
                goods.setTotalFee(orderProduct.getRealAmount() != null ? MoneyUtils.yuanToFen(String.valueOf(orderProduct.getRealAmount())) : MoneyUtils.yuanToFen(String.valueOf(new BigDecimal(0))));
                yaDunOrderDTO.getGoods().add(goods);

                if (orderProduct.getType() == 1) {
                    orderItemDO.setPromotionAmount(orderProduct.getPromotionAmount());
                    orderItemDO.setCouponAmount(new BigDecimal(0));
                    orderItemDO.setIntegrationAmount(new BigDecimal(0));
                    integrationAmount.add(orderItemDO.getIntegrationAmount());
                    orderItemDO.setTotalAmount(orderProduct.getTotalAmount());
                    orderItemDO.setRealAmount(orderProduct.getRealAmount());
                } else {
                    orderItemDO.setPromotionAmount(new BigDecimal(0));
                    orderItemDO.setCouponAmount(new BigDecimal(0));
                    orderItemDO.setIntegrationAmount(new BigDecimal(0));
                    orderItemDO.setTotalAmount(new BigDecimal(0));
                    orderItemDO.setRealAmount(new BigDecimal(0));
                }
                orderItems.add(orderItemDO);
            }
            yaDunOrderDTO.setDiscountFee(yaDunOrderDTO.getDiscountFee() + MoneyUtils.yuanToFen(String.valueOf(integrationAmount)));
            yaDunOrderDTO.setTotalFee(yaDunOrderDTO.getTotalFee() - MoneyUtils.yuanToFen(String.valueOf(integrationAmount)));
            orderDO.setIntegration(integration);
            orderDO.setIntegrationAmount(integrationAmount);
            int insert = this.baseMapper.insert(orderDO);
            if (insert <= 0) {
                throw new BaseException("添加订单失败");
            }
            CompletableFuture.runAsync(() -> {
                useCoupon(orderDO);
            }, executor);
            orderItems = orderItems.stream().map(orderItemDO -> orderItemDO.setOrderId(orderDO.getId())).collect(Collectors.toList());
            boolean saveBatchOrderItem = orderItemService.saveBatch(orderItems);
            if (!saveBatchOrderItem) {
                throw new BaseException("添加订单item失败");
            }
            MyWXConfig config = new MyWXConfig();
            WXPay wxpay = new WXPay(config);
            String nonceStr = WXPayUtil.generateNonceStr();
            Map<String, String> params = new HashMap<>();
            List<DeductionStockDTO> deductionStocks = placeOrderParams(createOrderDTO, request, orderDO, nonceStr, params);
            Map<String, String> stringStringMap = wxpay.unifiedOrder(params);
            log.info("微信统一下单返回结果:{}", JSON.toJSONString(stringStringMap));
            if ("SUCCESS".equals(stringStringMap.get("result_code"))) {
                Map<String, String> wxPayVO = getWxPayVO(nonceStr, stringStringMap);
                wxPayVO.put("orderId", orderDO.getId().toString());
                log.info("返回数据:{}", JSON.toJSONString(wxPayVO));
                // 发送延时mq
                boolean b = orderMessageSender.sendTimeOutOrderMessage(orderDO.getOrderSn());
                if (b) {
                    log.info("延迟消息发送成功");
                    // 维护数据到redis支付成功进行处理
                    maintenanceInfoToRedis(createOrderDTO, orderDO, orderItems, deductionStocks, wxPayVO, Collections.singletonList(yaDunOrderDTO));
                    return Result.success(wxPayVO);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("创建订单失败:{}", e.getMessage());
            throw new BaseException("创建订单失败");
        }
        throw new BaseException("创建订单失败");
    }


    @Override
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信回调!!!");
        try {
            // 获取请求体的输入流
            ServletInputStream inputStream = request.getInputStream();
            // 读取请求体的数据
            String xml = IOUtils.toString(inputStream);
            Map<String, String> map = WXPayUtil.xmlToMap(xml);
            log.info("支付返回:{}", JSON.toJSONString(map));
            String returnCode = MapUtils.getString(map, "return_code");
            if (!WXPayUtil.isSignatureValid(map, WxConstact.KEY)) {
                weChatNotifyResponse("FAIL", "签名失败", response);
                return;
            }
            if ("FAIL".equals(returnCode)) {
                String returnMsg = MapUtils.getString(map, "return_msg");
                log.error("支付异常：{}", returnMsg);
                weChatNotifyResponse("FAIL", returnMsg, response);
            }
            if ("SUCCESS".equals(returnCode)) {
                checkOrder(map);
                weChatNotifyResponse("SUCCESS", "OK", response);
            }
        } catch (Exception e) {
            log.error("微信回调处理异常:{}", e);
        }
    }

    //public static void main(String[] args) {
    //    String value = "[{\"address\":\"坂田街道天安云谷903\",\"brand\":1000001828,\"city\":\"深圳市\",\"customer_id\":\"M27813220081235499\",\"discountFee\":0,\"district\":\"龙岗区\",\"goods\":[{\"discountFee\":0,\"goodsName\":\"雅顿白茶护手霜 30ml\",\"num\":1,\"price\":11000,\"sku\":\"7227599000\",\"totalFee\":11000}],\"goodsFee\":11000,\"mobile\":\"15074150969\",\"orderId\":\"HS202317616000007\",\"payTime\":1687682316164,\"province\":\"广东省\",\"receiverName\":\"李嘉俊\",\"shippingFee\":0,\"totalFee\":11000}]";
    //    List<YaDunOrderDTO> yaDunOrderDTOS = JSONArray.parseArray(value, YaDunOrderDTO.class);
    //    yaDunOrderDTOS.get(0).setPayTime(new Date());
    //    String yaDunOrderDTOData = JSON.toJSONString(yaDunOrderDTOS);
    //    System.out.println(yaDunOrderDTOData);
    //}

    /**
     * 支付成功处理
     *
     * @param map
     */
    @GlobalTransactional(name = "Deduction-Stock-TX", rollbackFor = Exception.class)
    @Override
    public void updateStatusDeductionStock(Map<String, String> map) {
        log.info("处理支付成功事件！！");
        String outTradeNo = map.get("out_trade_no");
        String transactionId = map.get("transaction_id");
        String attach = redisUtil.getString(RedisKeyPrefix.GOODS_NUM + outTradeNo);
        LambdaQueryWrapper<OrderDO> queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                .eq(OrderDO::getOrderSn, outTradeNo);
        OrderDO orderDO = this.getOne(queryWrapper);
        // 修改状态
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getPayStatus, 1)
                .set(OrderDO::getPaymentTime, new Date())
                .set(OrderDO::getTransactionId, transactionId)
                .eq(OrderDO::getOrderSn, outTradeNo);
        this.update(uw);
        try {
            // 扣减库存
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                List<DeductionStockDTO> deductionStocks = JSONArray.parseArray(attach, DeductionStockDTO.class);
                Result result = goodsFeignClient.deductionStock(deductionStocks);
                if (!result.getStatus()) {
                    throw new BaseException("扣减库存失败" + result.getMessage());
                }
                redisUtil.del(RedisKeyPrefix.GOODS_NUM + outTradeNo);
                log.info("扣减库存成功");
            }, executor);

            // 添加积分
            CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
                AddIntegrationDTO addIntegrationDTO = new AddIntegrationDTO(orderDO.getPayerOpenId(), orderDO.getIntegration());
                Result addIntegrationResult = userFeignClient.addIntegration(addIntegrationDTO);
                if (!addIntegrationResult.getStatus()) {
                    throw new BaseException("添加积分失败" + addIntegrationResult.getMessage());
                }
                log.info("添加积分失败成功");
            }, executor);
            CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
                String data = redisUtil.hget(RedisKeyPrefix.HUISHU_YADUN_DATA, orderDO.getOrderSn());
                List<YaDunOrderDTO> yaDunOrderDTOS = JSONArray.parseArray(data, YaDunOrderDTO.class);
                yaDunOrderDTOS.get(0).setPayTime(new Date());
                String yaDunOrderDTOData = JSON.toJSONString(yaDunOrderDTOS);
                log.info("调用雅顿接口参数:{}", yaDunOrderDTOData);
                // 调用雅顿创建订单接口
                String content = requestYaDunApi(yaDunOrderDTOData, yaDunApiInfoEntity.getUrl());
                log.info("content:{}", content);
                JSONObject jsonObject = JSONObject.parseObject(content);
                Boolean success = jsonObject.getBoolean("success");
                if (!success) {
                    log.error("调用雅顿接口失败:{}", content);
                    throw new BaseException("调用雅顿接口失败" + content);
                }
                redisUtil.hdel(RedisKeyPrefix.HUISHU_YADUN_DATA, orderDO.getOrderSn());
                log.info("调用雅顿接口成功:{}", content);
            }, executor);
            CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
                redisUtil.del(RedisKeyPrefix.CARTITEM_IDS + orderDO.getUserId() + ":" + orderDO.getOrderSn());
                //// 处理样品只能购买一次
                //String value = redisUtil.getString(RedisKeyPrefix.SAMPLE_LIMITATION + orderDO.getOrderSn());
                //if (value != null) {
                //    List<Long> sampleIds = JSONArray.parseArray(value, Long.class);
                //    for (Long sampleId : sampleIds) {
                //        redisUtil.hdel(RedisKeyPrefix.SAMPLE_LIMITATION + orderDO.getUserId(), sampleId.toString());
                //    }
                //}
            }, executor);
            CompletableFuture<Void> allOf = CompletableFuture.allOf(future, future1, future2, future3);
            allOf.get();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("处理支付成功失败:{}", e.getMessage());
        }
    }

    @GlobalTransactional(name = "Rollback-Stock-TX", rollbackFor = Exception.class)
    @Override
    public void cancelOrderRollbackStock(String outTradeNo) {
        LambdaQueryWrapper<OrderDO> queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                .eq(OrderDO::getOrderSn, outTradeNo);
        OrderDO orderDO = this.getOne(queryWrapper);
        // 判断是否最后一秒支付
        if (orderDO.getPayStatus() == 1) {
            return;
        }
        String attach = redisUtil.getString(RedisKeyPrefix.GOODS_NUM + outTradeNo);
        // 修改状态
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getPayStatus, 2)
                .set(OrderDO::getOrderStatus, 4)
                .eq(OrderDO::getOrderSn, outTradeNo);
        this.update(uw);
        // 退回优惠卷
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            // 查询是否使用优惠卷
            LambdaQueryWrapper<OrderCouponDO> queryWrapperOrderCouponDO = Wrappers.lambdaQuery(OrderCouponDO.class)
                    .eq(OrderCouponDO::getOrderSn, outTradeNo);
            List<OrderCouponDO> orderCoupons = orderCouponService.list(queryWrapperOrderCouponDO);
            if (CollectionUtils.isNotEmpty(orderCoupons)) {
                List<Long> couponIds = orderCoupons.stream().map(OrderCouponDO::getCouponId).collect(Collectors.toList());
                //调用fegin
                ReturnUserCouponDTO returnUserCouponDTO = new ReturnUserCouponDTO();
                returnUserCouponDTO.setCouponIds(couponIds);
                returnUserCouponDTO.setUserId(orderDO.getUserId());
                Result result = couponFeignClient.returnUserCoupon(returnUserCouponDTO);
                if (!result.getStatus()) {
                    throw new BaseException("退回优惠卷失败" + result.getMessage());
                }
                List<Long> collect = orderCoupons.stream().map(OrderCouponDO::getId).collect(Collectors.toList());
                orderCouponService.removeByIds(collect);
            }
            log.info("退回优惠卷成功！！");
        }, executor);

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            // 回滚库存
            List<DeductionStockDTO> deductionStocks = JSONArray.parseArray(attach, DeductionStockDTO.class);
            for (DeductionStockDTO deductionStock : deductionStocks) {
                String key = RedisKeyPrefix.HUISHU_STOCK_CACHE_PREFIX + deductionStock.getProductId().toString();
                if (redisUtil.hasKey(key)) {
                    redisUtil.incr(key, deductionStock.getNum());
                }
                cache.remove(key);
            }
            if (StringUtils.isNotEmpty(orderDO.getWelfareCode())) {
                redisUtil.del(RedisKeyPrefix.WELFARE_CODE + orderDO.getWelfareCode() + orderDO.getUserId());
            }
            redisUtil.del(RedisKeyPrefix.GOODS_NUM + outTradeNo);
            log.info("回滚库存成功！！！");
        }, executor);

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            String value = redisUtil.getString(RedisKeyPrefix.CARTITEM_IDS + orderDO.getUserId() + ":" + orderDO.getOrderSn());
            List<Long> ids = JSONArray.parseArray(value, Long.class);
            LambdaUpdateWrapper<CartItemDO> uw1 = Wrappers.lambdaUpdate(CartItemDO.class)
                    .set(CartItemDO::getIsDelete, false)
                    .in(CartItemDO::getId, ids);
            boolean update = cartItemService.update(uw1);
            if (update) {
                redisUtil.del(RedisKeyPrefix.CARTITEM_IDS + orderDO.getUserId() + ":" + orderDO.getOrderSn());
                log.info("购物车商品恢复成功！！");
            }
        }, executor);
        // 处理样品只能购买一次
        String value = redisUtil.getString(RedisKeyPrefix.SAMPLE_LIMITATION + orderDO.getOrderSn());
        if (value != null) {
            List<Long> sampleIds = JSONArray.parseArray(value, Long.class);
            for (Long sampleId : sampleIds) {
                redisUtil.hdel(RedisKeyPrefix.SAMPLE_LIMITATION + orderDO.getUserId(), sampleId.toString());
            }
        }
        CompletableFuture<Void> allOf = CompletableFuture.allOf(future, future1, future2);
        try {
            allOf.get();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("超时取消订单异常!!!，{}", e.getMessage());
        }
    }


    @Override
    public Result orderDetailed(Long id) {
        OrderDO orderDO = getById(id);
        // 查询orderitem
        LambdaQueryWrapper<OrderItemDO> queryWrapper = Wrappers.lambdaQuery(OrderItemDO.class)
                .eq(OrderItemDO::getOrderId, id);
        List<OrderItemDO> orderItems = orderItemService.list(queryWrapper);
        // 组合数据
        OrderDetailedVO orderDetailedVO = BeanUtils.copyProperties(orderDO, OrderDetailedVO.class);
        orderDetailedVO.getOrderItems().addAll(orderItems);
        // 查询物流消息
        LambdaQueryWrapper<OrderDeliveryDO> queryWrapperOrderDelivery = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                .eq(OrderDeliveryDO::getOrderSn, orderDO.getOrderSn());
        orderDetailedVO.setOrderDeliveryDO(orderDeliveryMapper.selectList(queryWrapperOrderDelivery));
        return Result.success(orderDetailedVO);
    }

    // type 0全部 1 待支付 2 待发货 3 已发货 4 已经签收(已完成)  5 退款
    @Override
    public Result findByType(Integer type) {
        LambdaQueryWrapper<OrderDO> queryWrapper = null;
        if (type == 0) {
            queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                    .eq(OrderDO::getDeleteStatus, 0)
                    .eq(OrderDO::getUserId, AssistantContext.getCurrentUid())
                    .orderByDesc(OrderDO::getCreatedDate);
        } else if (type == 1) {
            queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                    .eq(OrderDO::getDeleteStatus, 0)
                    .eq(OrderDO::getPayStatus, 0)
                    .eq(OrderDO::getUserId, AssistantContext.getCurrentUid())
                    .orderByDesc(OrderDO::getCreatedDate);
        } else if (type == 2) {
            queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                    .eq(OrderDO::getDeleteStatus, 0)
                    .eq(OrderDO::getPayStatus, 1)
                    .eq(OrderDO::getOrderStatus, 1)
                    //.and(QueryWrapper -> QueryWrapper.ne(OrderDO::getChargebackStatus, 1).or().ne(OrderDO::getChargebackStatus, 2))
                    .eq(OrderDO::getUserId, AssistantContext.getCurrentUid())
                    .orderByDesc(OrderDO::getCreatedDate);
        } else if (type == 3) {
            queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                    .eq(OrderDO::getDeleteStatus, 0)
                    .eq(OrderDO::getPayStatus, 1)
                    .eq(OrderDO::getOrderStatus, 2)
                    //.and(QueryWrapper -> QueryWrapper.ne(OrderDO::getChargebackStatus, 1).or().ne(OrderDO::getChargebackStatus, 2))
                    .eq(OrderDO::getUserId, AssistantContext.getCurrentUid())
                    .orderByDesc(OrderDO::getCreatedDate);
        } else if (type == 4) {
            queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                    .eq(OrderDO::getDeleteStatus, 0)
                    .eq(OrderDO::getConfirmStatus, 1)
                    .eq(OrderDO::getOrderStatus, 3)
                    //.and(QueryWrapper -> QueryWrapper.ne(OrderDO::getChargebackStatus, 1).or().ne(OrderDO::getChargebackStatus, 2))
                    .eq(OrderDO::getUserId, AssistantContext.getCurrentUid())
                    .orderByDesc(OrderDO::getCreatedDate);
        } else {
            queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                    .eq(OrderDO::getDeleteStatus, 0)
                    .eq(OrderDO::getOrderStatus, 5)
                    .eq(OrderDO::getUserId, AssistantContext.getCurrentUid())
                    .orderByDesc(OrderDO::getCreatedDate);
        }
        List<OrderDO> orders = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(orders)) {
            return Result.success();
        }
        List<Long> orderIds = orders.stream().map(OrderDO::getId).collect(Collectors.toList());
        LambdaQueryWrapper<OrderItemDO> orderItemQueryWrapper = Wrappers.lambdaQuery(OrderItemDO.class)
                .in(OrderItemDO::getOrderId, orderIds);
        List<OrderItemDO> orderItems = orderItemService.list(orderItemQueryWrapper);
        List<OrderItemDO> sampleOrderItem = orderItems.stream().filter(o -> o.getProductType() == 4).collect(Collectors.toList());
        Map<Long, Boolean> entry = null;
        if (CollectionUtils.isNotEmpty(sampleOrderItem)) {
            List<Long> productIds = sampleOrderItem.stream().map(OrderItemDO::getProductId).collect(Collectors.toList());
            Result<Map<Long, Boolean>> result = couponFeignClient.findRepurchaseByProductIds(productIds);
            if (!result.getStatus()) {
                throw new BaseException("获取样品绑定的优惠卷失败!!");
            }
            entry = result.getEntry();
        }

        Map<Long, List<OrderItemDO>> orderItemMap = orderItems.stream().collect(Collectors.groupingBy(OrderItemDO::getOrderId));

        LambdaQueryWrapper<OrderDeliveryDO> orderDeliveryDOLambdaQueryWrapper = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                .in(OrderDeliveryDO::getOrderId, orderIds);
        List<OrderDeliveryDO> orderDeliveryDOS = orderDeliveryMapper.selectList(orderDeliveryDOLambdaQueryWrapper);
        Map<Long, List<OrderDeliveryDO>> collect = new HashMap<>();
        if (CollectionUtils.isNotEmpty(orderDeliveryDOS)) {
            collect = orderDeliveryDOS.stream().collect(Collectors.groupingBy(OrderDeliveryDO::getOrderId));
        }
        Map<Long, List<OrderDeliveryDO>> finalCollect = collect;
        Map<Long, Boolean> finalEntry = entry;
        List<MyOrderVO> myOrders = orders.stream().map(orderDO -> {
            MyOrderVO myOrderVO = BeanUtils.copyProperties(orderDO, MyOrderVO.class);
            myOrderVO.setOrderItemSize(orderItemMap.get(orderDO.getId()).size());
            OrderItemDO orderItem = orderItemMap.get(orderDO.getId()).stream().filter(orderItemDO -> orderItemDO.getProductType() == 1 || orderItemDO.getProductType() == 4).collect(Collectors.toList()).get(0);
            if (!org.springframework.util.CollectionUtils.isEmpty(finalEntry)) {
                List<OrderItemDO> collect1 = orderItemMap.get(orderDO.getId()).stream().filter(orderItemDO -> orderItemDO.getProductType() == 1 || orderItemDO.getProductType() == 4).collect(Collectors.toList());
                for (OrderItemDO orderItemDO : collect1) {
                    Boolean b = finalEntry.get(orderItemDO.getProductId());
                    if (b != null) {
                        myOrderVO.setIsRepurchase(true);
                    }
                }
            }
            myOrderVO.setAlbumPics(orderItem.getAlbumPics());
            if (CollectionUtil.isNotEmpty(finalCollect)) {
                myOrderVO.setOrderDeliverys(finalCollect.get(orderDO.getId()));
            }
            return myOrderVO;
        }).collect(Collectors.toList());
        return Result.success(myOrders);
    }


    @Override
    public Result pageList(PageListDTO pageListDTO) {
        Page<PageListVO> page = new Page<PageListVO>(pageListDTO.getCurrPage(), pageListDTO.getPageSize());
        IPage<PageListVO> pageListVO = this.baseMapper.pageList(page, pageListDTO);
        List<PageListVO> records = pageListVO.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return Result.success(pageListVO);
        }
        List<Long> orderIds = records.stream().map(PageListVO::getId).collect(Collectors.toList());

        try {
            getData(records, orderIds);
            pageListVO.setRecords(records);
            return Result.success(pageListVO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("订单pageList异常！！");
            throw new BaseException("订单pageList异常" + e.getMessage());
        }
    }


    @Override
    public void export(PageListDTO pageListDTO, HttpServletResponse response) {
        int count = this.count();
        Page<PageListVO> page = new Page<PageListVO>(1, count);
        IPage<PageListVO> pageListVO = this.baseMapper.pageList(page, pageListDTO);
        List<PageListVO> records = pageListVO.getRecords();
        List<Long> orderIds = records.stream().map(PageListVO::getId).collect(Collectors.toList());
        try {
            getData(records, orderIds);

            List<OrderExecl> orderExecls = new ArrayList<>();
            threadsHandle(records, orderExecls);
            ExportUtil.export(response, OrderExecl.class, orderExecls);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("导出数据异常");
        }
    }

    @Override
    public Result consoleData(ConsoleDataDTO consoleDataDTO) {
        // 查询数量
        Map<String, Object> map = this.baseMapper.consoleConut();
        // 查询consoleData
        List<Map<String, Object>> maps = this.baseMapper.consoleData(consoleDataDTO);
        ConsoleDataVO consoleDataVO = new ConsoleDataVO();
        consoleDataVO.setConsoleConut(map);
        consoleDataVO.setConsoleData(maps);
        return Result.success(consoleDataVO);
    }


    @Override
    public Result updateAddress(UpdateAddressDTO updateAddressDTO) {
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getReceiverName, updateAddressDTO.getReceiverName())
                .set(OrderDO::getReceiverPhone, updateAddressDTO.getReceiverPhone())
                .set(OrderDO::getReceiverProvince, updateAddressDTO.getReceiverProvince())
                .set(OrderDO::getReceiverCity, updateAddressDTO.getReceiverCity())
                .set(OrderDO::getReceiverRegion, updateAddressDTO.getReceiverRegion())
                .set(OrderDO::getReceiverDetailAddress, updateAddressDTO.getReceiverDetailAddress())
                .eq(OrderDO::getId, updateAddressDTO.getId());
        boolean update = this.update(uw);
        return update ? Result.success() : Result.fail();
    }

    @GlobalTransactional(name = "Confirm-Order-TX", rollbackFor = Exception.class)
    @Override
    public Result confirm(Long id) {
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getConfirmStatus, 1)
                .set(OrderDO::getOrderStatus, 3)
                .set(OrderDO::getReceiveTime, new Date())
                .eq(OrderDO::getId, id);
        boolean update = this.update(uw);
        if (!update) {
            throw new BaseException("签收失败！！");
        }
        OrderDO orderDO = this.getById(id);
        // 判断是否存在样品--发放复购卷
        LambdaQueryWrapper<OrderItemDO> queryWrapper = Wrappers.lambdaQuery(OrderItemDO.class)
                .eq(OrderItemDO::getProductType, 4)
                .eq(OrderItemDO::getOrderId, orderDO.getId());
        List<OrderItemDO> list = orderItemService.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return Result.success();
        }
        List<Long> productIds = list.stream().map(OrderItemDO::getProductId).collect(Collectors.toList());
        SendRepurchaseDTO sendRepurchaseDTO = new SendRepurchaseDTO();
        sendRepurchaseDTO.setUserId(orderDO.getUserId());
        sendRepurchaseDTO.setProductIds(productIds);
        Result result = couponFeignClient.sendRepurchase(sendRepurchaseDTO);
        if (!result.getStatus()) {
            throw new BaseException("发放复购卷失败");
        }
       /* // 查询是否第一次签收
        LambdaQueryWrapper<OrderDO> queryWrapper = Wrappers.lambdaQuery(OrderDO.class)
                .eq(OrderDO::getUserId, orderDO.getUserId())
                .eq(OrderDO::getConfirmStatus, 1);
        List<OrderDO> list = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            log.info("发放复购卷!!");
            // 发放复购卷
            SendRepurchaseDTO sendRepurchaseDTO = new SendRepurchaseDTO();
            sendRepurchaseDTO.setPayAmount(orderDO.getPayAmount());
            sendRepurchaseDTO.setUserId(orderDO.getUserId());
            Result result = couponFeignClient.sendRepurchase(sendRepurchaseDTO);
            if (!result.getStatus()) {
                throw new BaseException("发放复购卷失败！！");
            }
        }*/
        return Result.success();
    }

    @Override
    public Result continuePay(String orderSn) {
        String value = redisUtil.getString(RedisKeyPrefix.WX_PAY_DATA + orderSn);
        if (value == null) {
            throw new BaseException("程序异常拉取支付数据为空:" + orderSn);
        }
        return Result.success(JSONObject.parseObject(value, Map.class));
    }

    @Override
    public Result<List<UserOrderInfoVO>> getOrderInfoByUserIds(List<Long> ids) {
        return Result.success(this.baseMapper.getOrderInfoByUserIds(ids));
    }


    @Transactional
    @Override
    public Result refund(Long id) {
        OrderDO orderDO = this.getById(id);
        String outRefundNo = redisUtil.getOrderNo("HS_REFUND");
        // 退款
        try {
            Map<String, String> refund = refund(orderDO, outRefundNo);
            log.info("退款返回消息：{}", JSON.toJSONString(refund));
            if ("SUCCESS".equals(refund.get("return_code"))) {
                saveRefundAndUpdateOrderStatus(id, orderDO, outRefundNo, refund);
                // 判断是否是首单退款
                //deleteRepurchase(orderDO);
                return Result.success();
            }
            log.error("退款失败:{}", JSON.toJSONString(refund));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("退款异常:{}", e.getMessage());
        }
        log.error("退款失败，退款订单号:{},订单号:{}", outRefundNo, orderDO.getOrderSn());
        return Result.fail("退款失败！");
    }

    @Override
    public Result applicationExchange(Long id) {
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getOrderStatus, 9)
                .set(OrderDO::getUpdatedDate, new Date())
                .eq(OrderDO::getId, id);
        return this.update(uw) ? Result.success() : Result.fail();
    }

    @Override
    public Result chargeback(Long id) {
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getOrderStatus, 10)
                .set(OrderDO::getUpdatedDate, new Date())
                .eq(OrderDO::getId, id);
        return this.update(uw) ? Result.success() : Result.fail();
    }

    @Transactional
    @Override
    public Result refundChargeback(Long id) {
        this.refund(id);
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getOrderStatus, 8)
                .set(OrderDO::getUpdatedDate, new Date())
                .eq(OrderDO::getId, id);
        this.update(uw);
        return Result.success();
    }

    @Transactional
    @Override
    public Result cancellation(Long id) {
        OrderDO orderDO = this.getById(id);
        // 调用雅顿订单取消接口
        YDcancellationAPI(orderDO);
        this.refund(id);
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getOrderStatus, 4)
                .set(OrderDO::getUpdatedDate, new Date())
                .eq(OrderDO::getId, id);
        this.update(uw);
        return Result.success();
    }

    @Override
    public Result applicationRefund(Long id) {
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getOrderStatus, 6)
                .set(OrderDO::getUpdatedDate, new Date())
                .eq(OrderDO::getId, id);
        return this.update(uw) ? Result.success() : Result.fail();
    }

    @Override
    public Result applicationRefundGoods(Long id) {
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getOrderStatus, 7)
                .set(OrderDO::getUpdatedDate, new Date())
                .eq(OrderDO::getId, id);
        return this.update(uw) ? Result.success() : Result.fail();
    }

    @Override
    public Result backgroundDetails(Long id) {
        OrderDO orderDO = this.getById(id);
        // 查询item
        try {
            LambdaQueryWrapper<OrderItemDO> queryWrapper = Wrappers.lambdaQuery(OrderItemDO.class)
                    .eq(OrderItemDO::getOrderId, id);
            List<OrderItemDO> orderItems = orderItemService.list(queryWrapper);
            // 查询是否使用优惠卷
            CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
                LambdaQueryWrapper<OrderCouponDO> queryWrapperOrderCoupon = Wrappers.lambdaQuery(OrderCouponDO.class)
                        .eq(OrderCouponDO::getOrderSn, orderDO.getOrderSn());
                List<OrderCouponDO> orderCoupons = orderCouponService.list(queryWrapperOrderCoupon);
                if (CollectionUtils.isEmpty(orderCoupons)) {
                    return null;
                }
                List<Long> couponIds = orderCoupons.stream().map(OrderCouponDO::getCouponId).collect(Collectors.toList());
                Result<List<CouponVO>> result = couponFeignClient.findByCouponIds(couponIds);
                if (!result.getStatus()) {
                    throw new BaseException("查询订单使用的优惠卷失败!!");
                }
                List<CouponVO> entry = result.getEntry();
                return entry.stream().map(CouponVO::getName).collect(Collectors.toList());
            }, executor);
            // 查询快递信息
            LambdaQueryWrapper<OrderDeliveryDO> orderDeliveryDOLambdaQueryWrapper = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                    .eq(OrderDeliveryDO::getOrderId, orderDO.getId());
            List<OrderDeliveryDO> orderDeliveryDOS = orderDeliveryMapper.selectList(orderDeliveryDOLambdaQueryWrapper);
            // 查询备注消息
            LambdaQueryWrapper<OrderRemarksDO> queryWrapperOrderRemarks = Wrappers.lambdaQuery(OrderRemarksDO.class)
                    .eq(OrderRemarksDO::getOrderId, orderDO.getId());
            List<OrderRemarksDO> orderRemarksDOS = orderRemarksService.list(queryWrapperOrderRemarks);

            // 组装数据
            BackgroundDetailsVO backgroundDetailsVO = BeanUtils.copyProperties(orderDO, BackgroundDetailsVO.class);
            backgroundDetailsVO.setCouponNames(future.get());
            backgroundDetailsVO.setOrderItems(orderItems);
            backgroundDetailsVO.setOrderDeliverys(orderDeliveryDOS);
            backgroundDetailsVO.setOrderRemarks(orderRemarksDOS);
            return Result.success(backgroundDetailsVO);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.fail();
    }

    @Transactional
    @Override
    public Result refuseRefund(Long id) {
        // 查询是否发货
        LambdaQueryWrapper<OrderDeliveryDO> queryWrapper = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                .eq(OrderDeliveryDO::getOrderId, id);
        List<OrderDeliveryDO> orderDeliverys = orderDeliveryMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(orderDeliverys)) {
            // 已发货状态
            LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                    .set(OrderDO::getOrderStatus, 2)
                    .eq(OrderDO::getId, id);
            this.update(uw);
        } else {
            // 代发货状态
            LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                    .set(OrderDO::getOrderStatus, 1)
                    .eq(OrderDO::getId, id);
            this.update(uw);
        }
        // 根据用户id查询手机号
        OrderDO orderDO = this.getById(id);
        UserDO userDO = getUserDO(orderDO.getUserId());
        // 发送短信
        if (TXCloudSmsUtil.sendSms(userDO.getPhone(), null, SmsTemplateCode.REFUSE_REFUND)) {
            return Result.success();
        }
        throw new BaseException("发送短信失败！！");
    }

    @Override
    public Result refuseChargeback(Long id) {
        // 查询是否发货
        LambdaQueryWrapper<OrderDeliveryDO> queryWrapper = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                .eq(OrderDeliveryDO::getOrderId, id);
        List<OrderDeliveryDO> orderDeliverys = orderDeliveryMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(orderDeliverys)) {
            // 已发货状态
            LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                    .set(OrderDO::getOrderStatus, 2)
                    .eq(OrderDO::getId, id);
            this.update(uw);
        } else {
            // 代发货状态
            LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                    .set(OrderDO::getOrderStatus, 1)
                    .eq(OrderDO::getId, id);
            this.update(uw);
        }
        // 根据用户id查询手机号
        OrderDO orderDO = this.getById(id);
        UserDO userDO = getUserDO(orderDO.getUserId());
        // 发送短信
        if (TXCloudSmsUtil.sendSms(userDO.getPhone(), null, SmsTemplateCode.REFUSAL_EXCHANGE_GOODS)) {
            return Result.success();
        }
        throw new BaseException("发送短信失败！！");
    }

    @Override
    public Result refuseChargebackRefund(Long id) {
        // 查询是否发货
        LambdaQueryWrapper<OrderDeliveryDO> queryWrapper = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                .eq(OrderDeliveryDO::getOrderId, id);
        List<OrderDeliveryDO> orderDeliverys = orderDeliveryMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(orderDeliverys)) {
            // 已发货状态
            LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                    .set(OrderDO::getOrderStatus, 2)
                    .eq(OrderDO::getId, id);
            this.update(uw);
        } else {
            // 代发货状态
            LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                    .set(OrderDO::getOrderStatus, 1)
                    .eq(OrderDO::getId, id);
            this.update(uw);
        }
        OrderDO orderDO = this.getById(id);
        UserDO userDO = getUserDO(orderDO.getUserId());
        // 发送短信
        if (TXCloudSmsUtil.sendSms(userDO.getPhone(), null, SmsTemplateCode.REFUSE_CHARGEBACK_REFUND)) {
            return Result.success();
        }
        throw new BaseException("发送短信失败！！");
    }

    /**
     * 获取用户信息
     *
     * @param userId
     * @return
     */
    private UserDO getUserDO(Long userId) {
        Result<UserDO> result = userFeignClient.getUserInfo(userId);
        if (!result.getStatus()) {
            // 查询失败
            throw new BaseException("获取用户信息失败!!");
        }
        return result.getEntry();
    }

    /**
     * 检查样品
     *
     * @param createOrderDTO
     * @return
     */
    private Result checkSample(CreateOrderDTO createOrderDTO) {
        List<CreateOrderDTO.OrderProduct> collect = createOrderDTO.getOrderProducts().stream().filter(orderProduct -> orderProduct.getType() == 4).collect(Collectors.toList());
        for (CreateOrderDTO.OrderProduct orderProduct : collect) {
            String hget = redisUtil.hget(RedisKeyPrefix.SAMPLE_LIMITATION + AssistantContext.getCurrentUid(), orderProduct.getId().toString());
            if (hget != null) {
                return Result.fail("当前商品每个ID限购1份");
            }
        }
        return Result.success();
    }

    /**
     * 雅顿取消接口
     *
     * @param orderDO
     */
    private void YDcancellationAPI(OrderDO orderDO) {
        Map<String, Object> map = new HashMap<>();
        map.put("platformOrderId", orderDO.getOrderSn());
        String content = requestYaDunApi(JSON.toJSONString(map), yaDunApiInfoEntity.getCancelSaleOrderUrl());
        log.info("content:{}", content);
        JSONObject jsonObject = JSONObject.parseObject(content);
        Boolean success = jsonObject.getBoolean("success");
        if (!success) {
            log.error("调用雅顿接口失败:{}", content);
            throw new BaseException("调用雅顿接口失败" + content);
        }
        log.info("调用雅顿取消订单接口成功:{}", content);
    }

    /**
     * 退款
     *
     * @param orderDO
     * @param outRefundNo
     * @return
     * @throws Exception
     */
    private Map<String, String> refund(OrderDO orderDO, String outRefundNo) throws Exception {
        MyWXConfig config = new MyWXConfig();
        WXPay wxpay = new WXPay(config);
        // 生成的随机字符串
        String nonceStr = WXPayUtil.generateNonceStr();
        Map<String, String> param = new TreeMap<>();
        param.put("nonce_str", nonceStr);
        param.put("out_refund_no", outRefundNo);
        param.put("out_trade_no", orderDO.getOrderSn());
        int amount = MoneyUtils.yuanToFen(String.valueOf(orderDO.getPayAmount()));
        param.put("total_fee", String.valueOf(amount));
        param.put("refund_fee", String.valueOf(amount));
        return wxpay.refund(param);
    }

    /**
     * 回收复购卷
     *
     * @param orderDO
     */
    private void deleteRepurchase(OrderDO orderDO) {
        LambdaQueryWrapper<OrderDO> queryWrapper1 = Wrappers.lambdaQuery(OrderDO.class)
                .eq(OrderDO::getUserId, orderDO.getUserId())
                .eq(OrderDO::getPayStatus, 1)
                .lt(OrderDO::getCreatedDate, orderDO.getCreatedDate());
        List<OrderDO> list = this.list(queryWrapper1);
        if (CollectionUtils.isEmpty(list)) {
            // 把复购卷删除
            Result result = couponFeignClient.deleteRepurchase(orderDO.getUserId());
            if (!result.getStatus()) {
                throw new BaseException("收回复购卷失败！！");
            }
        }
    }

    private void saveRefundAndUpdateOrderStatus(Long id, OrderDO orderDO, String outRefundNo, Map<String, String> refund) {
        RefundDO refundDO = new RefundDO();
        refundDO.setOpenId(orderDO.getPayerOpenId());
        refundDO.setOutRefundNo(outRefundNo);
        refundDO.setOutTradeNo(orderDO.getOrderSn());
        refundDO.setRefundId(MapUtils.getString(refund, "refund_id"));
        refundDO.setRefundFee(MapUtils.getInteger(refund, "total_fee"));
        refundDO.setTransactionId(MapUtils.getString(refund, "transaction_id"));
        refundService.save(refundDO);
        LambdaUpdateWrapper<OrderDO> uw = Wrappers.lambdaUpdate(OrderDO.class)
                .set(OrderDO::getOrderStatus, 5)
                .set(OrderDO::getUpdatedDate, new Date())
                .eq(OrderDO::getId, id);
        this.update(uw);
    }

    private void threadsHandle(List<PageListVO> records, List<OrderExecl> orderExecls) {
        // 一百条为基准为一个线程处理
        List<List<PageListVO>> groupList = CommonUtils.partition(records, 100);
        CountDownLatch countDownLatch = new CountDownLatch(groupList.size());
        ExecutorService executorService = Executors.newFixedThreadPool(groupList.size());
        for (int i = 0; i < groupList.size(); i++) {
            int finalI = i;
            executorService.execute(() -> {
                List<PageListVO> productDOList = groupList.get(finalI);
                List<OrderExecl> collect = productDOList.stream().map(pageList -> {
                    OrderExecl orderExecl = new OrderExecl();
                    orderExecl.setOrderSn(pageList.getOrderSn());
                    orderExecl.setCreateDate(DateUtils.parseDateToStr(pageList.getCreatedDate(), DateUtils.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS));
                    orderExecl.setPayAmount(pageList.getPayAmount());
                    orderExecl.setStatus(pageList.getOrderStatus());
                    orderExecl.setReceiverDetailAddress(pageList.getReceiverDetailAddress());
                    orderExecl.setGoods(pageList.getOrderItems().parallelStream().map(orderItemDO -> orderItemDO.getProductName() + " x " + orderItemDO.getProductQuantity())
                            .collect(Collectors.joining(",")));
                    if (pageList.getUserMemberVO() != null) {
                        orderExecl.setCustomName(pageList.getUserMemberVO().getName());
                        orderExecl.setCustomPhone(pageList.getUserMemberVO().getPhone());
                        orderExecl.setTierName(pageList.getUserMemberVO().getTierName());
                    }
                    if (CollectionUtils.isNotEmpty(pageList.getOrderDeliverys())) {
                        orderExecl.setDelivery(pageList.getOrderDeliverys().parallelStream().map(orderDeliveryDO ->
                                orderDeliveryDO.getDeliveryCompany() + " # " + orderDeliveryDO.getDeliverySn())
                                .collect(Collectors.joining(",")));
                    }
                    return orderExecl;
                }).collect(Collectors.toList());
                orderExecls.addAll(collect);
                countDownLatch.countDown();
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            executorService.shutdown();
        }
    }


    private void getData(List<PageListVO> records, List<Long> orderIds) throws InterruptedException, ExecutionException {
        CompletableFuture<Map<Long, List<OrderItemDO>>> future = CompletableFuture.supplyAsync(() -> {
            // 查询item
            LambdaQueryWrapper<OrderItemDO> queryWrapper = Wrappers.lambdaQuery(OrderItemDO.class)
                    .in(OrderItemDO::getOrderId, orderIds);
            List<OrderItemDO> orderItemDOS = orderItemService.list(queryWrapper);
            return orderItemDOS.stream().collect(Collectors.groupingBy(OrderItemDO::getOrderId));
        }, executor);


        CompletableFuture<Map<Long, List<OrderDeliveryDO>>> future1 = CompletableFuture.supplyAsync(() -> {
            // 查询快递信息
            LambdaQueryWrapper<OrderDeliveryDO> queryWrapper = Wrappers.lambdaQuery(OrderDeliveryDO.class)
                    .in(OrderDeliveryDO::getOrderId, orderIds);
            List<OrderDeliveryDO> orderDeliveryDOS = orderDeliveryMapper.selectList(queryWrapper);
            return orderDeliveryDOS.stream().collect(Collectors.groupingBy(OrderDeliveryDO::getOrderId));
        }, executor);

        CompletableFuture<Map<Long, UserMemberVO>> future2 = CompletableFuture.supplyAsync(() -> {
            List<Long> userIds = records.stream().map(PageListVO::getUserId).collect(Collectors.toList());
            // 查询用户信息
            List<Long> collect = userIds.stream().distinct().collect(Collectors.toList());
            Result<List<UserMemberVO>> result = userFeignClient.findUserMember(collect);
            if (!result.getStatus()) {
                throw new BaseException("查询用户会员数据异常！！");
            }
            return result.getEntry().parallelStream().collect(Collectors.toMap(UserMemberVO::getUserId, userMemberVO -> userMemberVO));
        }, executor);
        CompletableFuture<Void> allOf = CompletableFuture.allOf(future, future1, future2);
        allOf.get();

        for (PageListVO record : records) {
            record.setOrderItems(future.get().get(record.getId()));
            record.setOrderDeliverys(future1.get().get(record.getId()));
            record.setUserMemberVO(future2.get().get(record.getUserId()));
        }
    }

    /**
     * 微信通知返回
     *
     * @param code
     * @param msg
     * @param response
     * @throws Exception
     */
    private void weChatNotifyResponse(String code, String msg, HttpServletResponse response) throws Exception {
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("return_code", code);
        resultMap.put("return_msg", msg);
        PrintWriter writer = response.getWriter();
        writer.write(WXPayUtil.mapToXml(resultMap));
        writer.flush();
        writer.close();
    }

    private void maintenanceOrderCoupon(List<Long> couponIds, String orderSn) {
        //todo 假如用户在优惠卷过期的最后一秒使用--判断使用的优惠卷是否过期
        List<OrderCouponDO> orderCoupons = couponIds.stream().map(l -> {
            OrderCouponDO orderCouponDO = new OrderCouponDO();
            orderCouponDO.setCouponId(l);
            orderCouponDO.setOrderSn(orderSn);
            return orderCouponDO;
        }).collect(Collectors.toList());
        boolean b = orderCouponService.saveBatch(orderCoupons);
        if (!b) {
            throw new BaseException("维护订单优惠卷数据失败");
        }
    }


    private void useCoupon(OrderDO orderDO) {
        // 查询是否使用优惠卷
        LambdaQueryWrapper<OrderCouponDO> queryWrapperOrderCouponDO = Wrappers.lambdaQuery(OrderCouponDO.class)
                .eq(OrderCouponDO::getOrderSn, orderDO.getOrderSn());
        List<OrderCouponDO> orderCoupons = orderCouponService.list(queryWrapperOrderCouponDO);
        if (CollectionUtils.isNotEmpty(orderCoupons)) {
            // 标记用户优惠卷已使用
            List<UseCouponDTO> collect = orderCoupons.stream().map(orderCouponDO -> {
                return new UseCouponDTO(orderCouponDO.getCouponId(), orderDO.getUserId(), orderDO.getId(), orderDO.getOrderSn());
            }).collect(Collectors.toList());

            Result useCouponResult = couponFeignClient.useCoupon(collect);
            if (!useCouponResult.getStatus()) {
                log.error("调用标记使用优惠卷接口失败：{}", useCouponResult.getMessage());
                throw new BaseException("调用标记使用优惠卷接口失败" + useCouponResult.getMessage());
            }
        }
    }

    /**
     * 检查订单
     *
     * @param map
     */
    private void checkOrder(Map<String, String> map) {
        String outTradeNo = map.get("out_trade_no");
        String transactionId = map.get("transaction_id");
        log.info("回调数据outTradeNo:{},transactionId:{}", outTradeNo, transactionId);
        LambdaQueryWrapper<OrderDO> queryWrapper = Wrappers.lambdaQuery(OrderDO.class);
        queryWrapper.eq(OrderDO::getOrderSn, outTradeNo);
        OrderDO orderDO = this.getOne(queryWrapper);
        if (orderDO != null) {
            if (orderDO.getPayStatus() == 0) {
                // 发送mq修改订单状态  扣减库存
                orderMessageSender.sendUpdateOrderMsg(map);
            }
        }

    }

    private Result checkStock(CreateOrderDTO createOrderDTO) {
        ReentrantLock reentrantLock = new ReentrantLock(true);
        try {
            reentrantLock.lock();
            Map<String, Integer> map = new HashMap<>();
            // 预扣库存
            for (CreateOrderDTO.OrderProduct orderProduct : createOrderDTO.getOrderProducts()) {
                if (orderProduct.getType() != 1) {
                    continue;
                }
                String key = RedisKeyPrefix.HUISHU_STOCK_CACHE_PREFIX + orderProduct.getId().toString();
                map.put(key, orderProduct.getNum());
                Boolean localcache = cache.getCache(key);
                if (localcache != null && localcache) {
                    // orderProduct.getName() + "商品库存不足,请购买其它商品或者请等待工作人员补充库存!"
                    return Result.fail("您当前订单中有商品库存不足!");
                }
                Long stock = stockService.stock(key, orderProduct.getNum());
                if (stock == 0) {
                    cache.setLocalCache(key, true);
                }
                if (stock == -2) {
                    //// 回滚
                    //map.forEach((k, v) -> {
                    //    redisUtil.incr(k, v);
                    //});
                    return Result.fail("您当前订单中有商品库存不足!");
                }
            }
        } finally {
            reentrantLock.unlock();
        }
        return Result.success();
    }


    /**
     * 返回前端的值
     *
     * @param nonceStr
     * @param stringStringMap
     * @return
     * @throws Exception
     */
    private Map<String, String> getWxPayVO(String nonceStr, Map<String, String> stringStringMap) throws Exception {
        Map<String, String> payparamsMap = new HashMap<String, String>();
        Date currDate = new Date();
        long timestamp = currDate.getTime() / 1000;
        payparamsMap.put("appId", WxConstact.APPID);
        payparamsMap.put("package", "prepay_id=" + stringStringMap.get("prepay_id"));
        payparamsMap.put("timeStamp", timestamp + "");
        payparamsMap.put("nonceStr", WXPayUtil.generateNonceStr());//
        payparamsMap.put("signType", WXPayConstants.MD5);
        String newSign = WXPayUtil.generateSignature(payparamsMap, WxConstact.KEY, WXPayConstants.SignType.MD5);
        payparamsMap.put("paySign", newSign);
        log.info("response data:" + JSON.toJSONString(payparamsMap));
        return payparamsMap;
    }

    /**
     * 调用雅顿接口
     *
     * @param data
     * @return
     */
    private String requestYaDunApi(String data, String url) {
        SortedMap<Object, Object> map = new TreeMap<Object, Object>();
        String random = RandomUtil.randomNumbers(5);
        String timestamp = String.valueOf(Calendar.getInstance().getTimeInMillis());
        log.info("data:{}", data);
        map.put("appKey", yaDunApiInfoEntity.getAppKey());
        map.put("appSecret", yaDunApiInfoEntity.getAppSecret());
        map.put("random", random);
        map.put("timestamp", timestamp);
        map.put("data", data);
        // 获取sign
        String valeu = createSign("UTF-8", map);
        String sign = MD5Utils.hexMd5(valeu).toUpperCase();
        map.put("sign", sign);
        HttpClientUtil httpClient = new HttpClientUtil(url);
        httpClient.setHttps(true);
        httpClient.setBody(JSON.toJSONString(map));
        httpClient.post();
        return httpClient.getContent();
    }

    private YaDunOrderDTO createYaDunOrderDTO(CreateOrderDTO createOrderDTO, String orderNo) {
        YaDunOrderDTO yaDunOrderDTO = new YaDunOrderDTO();
        yaDunOrderDTO.setOrderId(orderNo);
        yaDunOrderDTO.setBrand(yaDunApiInfoEntity.getShopid());
        yaDunOrderDTO.setTotalFee(MoneyUtils.yuanToFen(String.valueOf(createOrderDTO.getPayAmount())));
        yaDunOrderDTO.setShippingFee(MoneyUtils.yuanToFen(String.valueOf(createOrderDTO.getFreightAmount())));
        yaDunOrderDTO.setDiscountFee(MoneyUtils.yuanToFen(String.valueOf(createOrderDTO.getCouponAmount().add(createOrderDTO.getPromotionAmount()))));
        yaDunOrderDTO.setGoodsFee(MoneyUtils.yuanToFen(String.valueOf(createOrderDTO.getTotalAmount())));
        yaDunOrderDTO.setReceiverName(createOrderDTO.getReceiverName());
        yaDunOrderDTO.setProvince(createOrderDTO.getReceiverProvince());
        yaDunOrderDTO.setCity(createOrderDTO.getReceiverCity());
        yaDunOrderDTO.setDistrict(createOrderDTO.getReceiverRegion());
        yaDunOrderDTO.setAddress(createOrderDTO.getReceiverDetailAddress());
        yaDunOrderDTO.setMobile(createOrderDTO.getReceiverPhone());
        Result<String> userMemberCode = userFeignClient.getUserMemberCode(AssistantContext.getCurrentUid());
        if (!userMemberCode.getStatus()) {
            throw new BaseException("获取用户会员码失败!! " + userMemberCode.getMessage());
        }
        yaDunOrderDTO.setCustomer_id(userMemberCode.getEntry() == null ? "HS999" : userMemberCode.getEntry());
        yaDunOrderDTO.setPayTime(new Date());
        return yaDunOrderDTO;
    }

    private OrderDO createOderDO(CreateOrderDTO createOrderDTO, String orderNo) {
        OrderDO orderDO = new OrderDO();

        // 订单金额信息
        orderDO.setOrderSn(orderNo);
        orderDO.setUserId(AssistantContext.getCurrentUid());
        orderDO.setTotalAmount(createOrderDTO.getTotalAmount());
        orderDO.setPayAmount(createOrderDTO.getPayAmount());
        orderDO.setFreightAmount(createOrderDTO.getFreightAmount());
        orderDO.setPromotionAmount(createOrderDTO.getPromotionAmount());
        orderDO.setIntegration(0);
        orderDO.setCouponAmount(createOrderDTO.getCouponAmount());
        // 备注
        orderDO.setNote(createOrderDTO.getNote());
        // 发票
        orderDO.setBillType(createOrderDTO.getBillType());
        orderDO.setBillReceiverName(createOrderDTO.getBillReceiverName());
        orderDO.setBillReceiverPhone(createOrderDTO.getBillReceiverPhone());
        orderDO.setBillReceiverProvince(createOrderDTO.getBillReceiverProvince());
        orderDO.setBillReceiverCity(createOrderDTO.getBillReceiverCity());
        orderDO.setBillReceiverRegion(createOrderDTO.getBillReceiverRegion());
        orderDO.setBillReceiverDetailAddress(createOrderDTO.getBillReceiverDetailAddress());
        // 收货地址
        orderDO.setReceiverName(createOrderDTO.getReceiverName());
        orderDO.setReceiverPhone(createOrderDTO.getReceiverPhone());
        orderDO.setReceiverProvince(createOrderDTO.getReceiverProvince());
        orderDO.setReceiverCity(createOrderDTO.getReceiverCity());
        orderDO.setReceiverRegion(createOrderDTO.getReceiverRegion());
        orderDO.setReceiverDetailAddress(createOrderDTO.getReceiverDetailAddress());
        orderDO.setWelfareCode(createOrderDTO.getWelfareCode());
        // openId
        orderDO.setPayerOpenId(AssistantContext.currentUser().getOpenId());
        return orderDO;
    }


    private static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        StringBuffer sbkey = new StringBuffer();
        Set es = parameters.entrySet();  //所有参与传参的参数按照accsii排序（升序）
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            //空值不传递，不参与签名组串
            if (null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
                sbkey.append(k + "=" + v + "&");
            }
        }
        //System.out.println("字符串:"+sb.toString());
        sbkey.deleteCharAt(sb.length() - 1);
        return sbkey.toString();
    }

    /***
     * 维护信息到redis，支付成功后处理数据
     * @param createOrderDTO
     * @param orderDO
     * @param orderItems
     * @param deductionStocks
     * @param wxPayVO
     */
    private void maintenanceInfoToRedis(CreateOrderDTO createOrderDTO, OrderDO orderDO, List<OrderItemDO> orderItems,
                                        List<DeductionStockDTO> deductionStocks,
                                        Map<String, String> wxPayVO,
                                        List<YaDunOrderDTO> yaDunOrders) {
        if (StringUtils.isNotEmpty(createOrderDTO.getWelfareCode())) {
            redisUtil.set(RedisKeyPrefix.WELFARE_CODE + createOrderDTO.getWelfareCode() + ":" + AssistantContext.getCurrentUid(), createOrderDTO.getWelfareCode());
        }
        if (CollectionUtils.isNotEmpty(createOrderDTO.getCartItemIds())) {
            redisUtil.set(RedisKeyPrefix.CARTITEM_IDS + AssistantContext.getCurrentUid() + ":" + orderDO.getOrderSn(), JSON.toJSONString(createOrderDTO.getCartItemIds()));
            LambdaUpdateWrapper<CartItemDO> uw = Wrappers.lambdaUpdate(CartItemDO.class)
                    .set(CartItemDO::getIsDelete, true)
                    .in(CartItemDO::getId, createOrderDTO.getCartItemIds());
            cartItemService.update(uw);
        }
        List<OrderItemDO> sample = orderItems.stream().filter(orderItem -> orderItem.getProductType() == 4).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(sample)) {
            List<Long> sampleIds = sample.stream().map(OrderItemDO::getProductId).collect(Collectors.toList());
            redisUtil.set(RedisKeyPrefix.SAMPLE_LIMITATION + orderDO.getOrderSn(), JSON.toJSONString(sampleIds));
            // 处理样品只能购买一次
            for (Long sampleId : sampleIds) {
                redisUtil.hset(RedisKeyPrefix.SAMPLE_LIMITATION + orderDO.getUserId(), sampleId.toString(), "1");
            }
        }
        redisUtil.set(RedisKeyPrefix.WX_PAY_DATA + orderDO.getOrderSn(), JSON.toJSONString(wxPayVO), 1200000);
        redisUtil.set(RedisKeyPrefix.GOODS_NUM + orderDO.getOrderSn(), JSON.toJSONString(deductionStocks));
        log.info("雅顿订单数据:{}", JSON.toJSONString(yaDunOrders));
        redisUtil.hset(RedisKeyPrefix.HUISHU_YADUN_DATA, orderDO.getOrderSn(), JSON.toJSONString(yaDunOrders));
        wxPayVO.put("cartItemCount", String.valueOf(cartItemService.cartItemCount(AssistantContext.getCurrentUid())));
    }

    /**
     * 构建下单参数
     *
     * @param createOrderDTO
     * @param request
     * @param orderDO
     * @param nonceStr
     * @param params
     * @return
     * @throws Exception
     */
    private List<DeductionStockDTO> placeOrderParams(CreateOrderDTO createOrderDTO, HttpServletRequest request, OrderDO orderDO, String nonceStr, Map<String, String> params) throws Exception {
        params.put("nonce_str", nonceStr);
        params.put("body", "购买商品");
        List<DeductionStockDTO> deductionStocks = createOrderDTO.getOrderProducts().stream()
                .filter(orderProduct -> orderProduct.getType() == 1).map(orderProduct -> {
                    DeductionStockDTO deductionStockDTO = new DeductionStockDTO();
                    deductionStockDTO.setProductId(orderProduct.getId());
                    deductionStockDTO.setNum(orderProduct.getNum());
                    return deductionStockDTO;
                }).collect(Collectors.toList());
        params.put("attach", JSON.toJSONString(deductionStocks));
        params.put("out_trade_no", orderDO.getOrderSn());
        // 支付金额，这边需要转成字符串类型，否则后面的签名会失败
        int i = MoneyUtils.yuanToFen(String.valueOf(orderDO.getPayAmount()));
        params.put("total_fee", i + "");
        params.put("spbill_create_ip", IPUtils.getIp(request));
        params.put("notify_url", WxConstact.PAY_CALLBACK_URL);
        params.put("trade_type", WxConstact.TRADETYPE);
        params.put("openid", AssistantContext.currentUser().getOpenId());
        params.put("sign_type", WXPayConstants.MD5);

        String sign = WXPayUtil.generateSignature(params, WxConstact.KEY, WXPayConstants.SignType.MD5);
        // 签名
        params.put("sign", sign);
        log.info("统一下单参数：{}", JSON.toJSONString(params));
        return deductionStocks;
    }

   /* @Data
    public static class TestOrder {
        private Integer brand = 1000002159;

        private String orderId = "DD20230412XXX";

        private Date payTime = new Date();

        private BigDecimal totalFee = new BigDecimal(180);

        private BigDecimal shippingFee = new BigDecimal(0);

        private BigDecimal discountFee = new BigDecimal(20);

        private BigDecimal goodsFee = new BigDecimal(200);

        private String receiverName = "张三";

        private String province = "广东";

        private String city = "深圳";

        private String district = "龙岗";

        private String address = "广东省深圳市龙岗区天安云谷";

        private String mobile = "11111111111";

        private String customer_id = "HS999";

        private List<Goods> goods = new ArrayList<>();
    }

    @Data
    public static class Goods {
        private String sku;

        private String goodsName;

        private Integer num;

        private BigDecimal price;

        private BigDecimal discountFee;

        private BigDecimal totalFee;
    }*/
}
